/*
 * Copyright (c) 2021 Contributors to the Eclipse Foundation
 * 
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 * 
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 * 
 * SPDX-License-Identifier: EPL-2.0
 */
package com.ibm.ima.mqcon.utils;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Session;

import com.ibm.ima.jms.ImaJmsFactory;
import com.ibm.ima.jms.ImaProperties;
import com.ibm.msg.client.jms.JmsConnectionFactory;
import com.ibm.msg.client.jms.JmsConstants;
import com.ibm.msg.client.jms.JmsFactoryFactory;
import com.ibm.msg.client.wmq.WMQConstants;

/**
 * Helper class for generating sessions for either IMA or MQ
 * 
 * TODO - add helper methods for generating connections with additional connection name-value properties 
 *
 */
public class JmsSession {
	
	public static enum CLIENT_TYPE {IMA, MQ} // used to distinguish client types
	
	private Connection connection = null;
	private String userId = "root"; // this has to be a valid user on the MQ box
	private String password = "thisIsNotValidatedByMQ"; // this is never checked with chlauth(disabled) 
	private CLIENT_TYPE type = null;
	private String channel = "SVT_MQCLIENTS";
	
	/**
	 * This method returns a session which uses the default IMA or MQ settings
	 * which are non transacted and auto message acknowledgement. No client
	 * ID is specified in the connection and thus one will be automatically
	 * generated by the appropriate JMS provider.
	 * 
	 * @return Session object
	 * @throws Exception
	 */
	public Session getSession(CLIENT_TYPE clientType, String hostname, int port, String queue_manager ) throws JMSException
	{
		ConnectionFactory cf = null;
		if(clientType.equals(CLIENT_TYPE.IMA))
		{
			cf = this.createIMAConnectionFactory(hostname, port);
			connection = cf.createConnection();
			type = CLIENT_TYPE.IMA;
		}
		else if(clientType.equals(CLIENT_TYPE.MQ))
		{
			cf = this.createMQConnectionFactory(hostname, port, queue_manager);
			connection = cf.createConnection(userId, password);		
			type = CLIENT_TYPE.MQ;
		}
	
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		return session;
	}
	
	/**
	 * This method returns a session which uses the default IMA or MQ settings
	 * which are non transacted and auto message acknowledgement. The specified client id
	 * will be used on the connection
	 * 
	 * @return Session object
	 * @throws Exception
	 */
	public Session getSession(CLIENT_TYPE clientType, String hostname, int port, String queue_manager, String clientId ) throws JMSException
	{
		ConnectionFactory cf = null;
		if(clientType.equals(CLIENT_TYPE.IMA))
		{
			cf = this.createIMAConnectionFactory(hostname, port);
			connection = cf.createConnection();
			connection.setClientID(clientId);
			type = CLIENT_TYPE.IMA;
		}
		else if(clientType.equals(CLIENT_TYPE.MQ))
		{
			cf = this.createMQConnectionFactory(hostname, port, queue_manager);
			connection = cf.createConnection(userId, password);
			connection.setClientID(clientId);
			type = CLIENT_TYPE.MQ;
		}
	
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		return session;
	}
	
	/**
	 * This method returns a session which uses the specified session settings
	 * for the session. No client ID is specified on the connection and thus
	 * one will be automatically generated by the JMS provider
	 * 
	 * @return Session object
	 * @throws Exception
	 */
	public Session getSession(CLIENT_TYPE clientType, String hostname, int port, String queue_manager, boolean transacted, int acknowledgement ) throws JMSException
	{
		ConnectionFactory cf = null;
		if(clientType.equals(CLIENT_TYPE.IMA))
		{
			cf = this.createIMAConnectionFactory(hostname, port);
			connection = cf.createConnection();
			type = CLIENT_TYPE.IMA;
		}
		else if(clientType.equals(CLIENT_TYPE.MQ))
		{
			cf = this.createMQConnectionFactory(hostname, port, queue_manager);
			connection = cf.createConnection(userId, password);
			type = CLIENT_TYPE.MQ;
		}
		
		Session session = connection.createSession(transacted, acknowledgement);
		return session;
	}
	
	/**
	 * This method returns a session which uses the specified session settings
	 * for the session. The specified client ID will be used on the connection
	 * 
	 * @return Session object
	 * @throws Exception
	 */
	public Session getSession(CLIENT_TYPE clientType, String hostname, int port, String queue_manager, String clientID, boolean transacted, int acknowledgement ) throws JMSException
	{
		ConnectionFactory cf = null;
		if(clientType.equals(CLIENT_TYPE.IMA))
		{
			cf = this.createIMAConnectionFactory(hostname, port);
			connection = cf.createConnection();
			connection.setClientID(clientID);
			type = CLIENT_TYPE.IMA;
		}
		else if(clientType.equals(CLIENT_TYPE.MQ))
		{
			cf = this.createMQConnectionFactory(hostname, port, queue_manager);
			connection = cf.createConnection(userId, password);
			connection.setClientID(clientID);
			type = CLIENT_TYPE.MQ;
		}
		

		
		Session session = connection.createSession(transacted, acknowledgement);
		return session;
	}
	
	public CLIENT_TYPE getClientType()
	{
		return type;
	}
	
	/**
	 * Use this method to start the connection. For consumers they will not receive 
	 * any messages until a connection is explicitly started
	 * @throws JMSException
	 */
	public void startConnection() throws JMSException
	{
		connection.start();
		
	}

	
	
	public Connection getConnection() throws JMSException
	{
		return connection;
		
	}
		
	/**
	 * Use this method to stop the connection. 
	 * @throws JMSException
	 */
	public void closeConnection() throws JMSException
	{
		if (connection !=null) {
		connection.close();
		}
	}
	
	/**
	 * Method to create a simple IMA connection factory
	 * @param hostname - fully qualified hostname or ip address of the IMA server
	 * @param port - port of the ima server
	 * @throws JMSException
	 */
	private ConnectionFactory createIMAConnectionFactory(String hostname, int port) throws JMSException
	{
		
		ConnectionFactory connectionFactory = ImaJmsFactory.createConnectionFactory();
		((ImaProperties) connectionFactory).put("Server", hostname);
		((ImaProperties) connectionFactory).put("Port", port);
		
		return connectionFactory;
		
	}
	
	/**
	 * Method to create a simple MQ connection Factory
	 * @param hostname
	 * @param port
	 * @throws JMSException
	 */
	private ConnectionFactory createMQConnectionFactory(String hostname, int port, String queueManager) throws JMSException
	{
		
		JmsFactoryFactory jmsff = JmsFactoryFactory.getInstance(JmsConstants.WMQ_PROVIDER);
		JmsConnectionFactory connectionFactory = jmsff.createConnectionFactory();
		connectionFactory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE,
                WMQConstants.WMQ_CM_CLIENT);
		connectionFactory.setStringProperty(WMQConstants.WMQ_HOST_NAME, hostname);
		connectionFactory.setIntProperty(WMQConstants.WMQ_PORT, port);
		connectionFactory.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManager);
		connectionFactory.setStringProperty(WMQConstants.WMQ_CHANNEL, channel);
		

		return connectionFactory;
	}

}
